﻿using ArcGIS.Core.CIM;
using ArcGIS.Core.Data;
using ArcGIS.Core.Geometry;
using ArcGIS.Desktop.Catalog;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Editing;
using ArcGIS.Desktop.Extensions;
using ArcGIS.Desktop.Framework;
using ArcGIS.Desktop.Framework.Contracts;
using ArcGIS.Desktop.Framework.Dialogs;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Layouts;
using ArcGIS.Desktop.Mapping;
using CCTool.Scripts.ToolManagers;
using CCTool.Scripts.ToolManagers.Extensions;
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using MessageBox = System.Windows.MessageBox;

namespace CCTool.Scripts.ProMapTool
{
    internal class SplitPolygon : MapTool
    {
        public SplitPolygon()
        {
            IsSketchTool = true;
            SketchType = SketchGeometryType.Line;
            SketchOutputMode = SketchOutputMode.Map;
            UseSnapping = true; // 默认启用捕捉环境
        }

        // 工具激活时，判断一下是否是有选择1个面要素
        protected async override Task OnToolActivateAsync(bool active)
        {
            await QueuedTask.Run(() =>
            {
                // 获取活动地图视图中选定的要素集合
                var selectedSet = MapView.Active.Map.GetSelection();

                // 将选定的要素集合转换为字典形式，就取第一个
                var layer = selectedSet.ToDictionary().FirstOrDefault();
                // 获取图层
                FeatureLayer featurelayer = layer.Key as FeatureLayer;
                // 图层类型
                var featureType = featurelayer.TargetGeoType();

                // 如果选择的不是1个面要素图斑，返回
                if (featureType != GeometryType.Polygon || selectedSet.Count != 1)
                {
                    MessageBox.Show("请选择1个面要素。");
                    return;
                }
            });
            await base.OnToolActivateAsync(active);
        }


        // 切割线绘制完成时，执行逻辑
        // 这里的输入参数是绘制的图形
        protected override async Task<bool> OnSketchCompleteAsync(Geometry geometry)
        {
            await QueuedTask.Run(() =>
            {
                double targetArea = 500;    // 指定面积
                double tolerance = 0.01;   // 容差
                
                // 获取切割线
                Polyline splitLine = geometry as Polyline;
                // 获取活动地图视图中选定的面要素
                Polygon selectPolygon = MapCtlTool.GetSelectedPolygon().FirstOrDefault();

                // 将splitLine的坐标系转换为selectPolygon的坐标系
                Polyline splitLinePro = GeometryEngine.Instance.Project(splitLine, selectPolygon.SpatialReference) as Polyline;

                if (splitLinePro == null || selectPolygon == null)
                {
                    MessageBox.Show("无有效切割线或未选择面要素");
                    return;
                }
                // 获取切割线的起点和终点
                var p0 = splitLinePro.Points[0];
                var p1 = splitLinePro.Points[^1];
                
                // 将splitLinePro的两端延伸10倍
                var dx = p1.X - p0.X;
                var dy = p1.Y - p0.Y;
                var extendedP0 = MapPointBuilderEx.CreateMapPoint(p0.X - dx * 10, p0.Y - dy * 10, selectPolygon.SpatialReference);
                var extendedP1 = MapPointBuilderEx.CreateMapPoint(p1.X + dx * 10, p1.Y + dy * 10, selectPolygon.SpatialReference);
                splitLinePro = PolylineBuilderEx.CreatePolyline(new List<MapPoint> { extendedP0, extendedP1 }, selectPolygon.SpatialReference);
                
                // 重新获取延伸后的起点和终点
                p0 = splitLinePro.Points[0];
                p1 = splitLinePro.Points[^1];
                var vx = p1.X - p0.X;
                var vy = p1.Y - p0.Y;
                var vlen = Math.Sqrt(vx * vx + vy * vy);
                if (vlen == 0)
                {
                    MessageBox.Show("切割线长度为0");
                    return;
                }
                var nx = -vy / vlen;
                var ny = vx / vlen;

                double? AreaAt(double offset)
                {
                    var moved = GeometryEngine.Instance.Move(splitLinePro, nx * offset, ny * offset) as Polyline;
                    var cutParts = GeometryEngine.Instance.Cut(selectPolygon, moved) as IReadOnlyList<Geometry>;
                    if (cutParts == null || cutParts.Count != 2) return null;
                    var part1 = cutParts[0] as Polygon;
                    if (part1 == null) return null;
                    return Math.Abs(GeometryEngine.Instance.Area(part1));
                }

                var extent = selectPolygon.Extent;
                double maxRange = Math.Max(extent.Width, extent.Height) * 2.0;
                double step = maxRange / 40.0;
                double? prevOffset = null;
                double? prevArea = null;
                bool bracketFound = false;
                double left = 0, right = 0;

                for (int i = 0; i <= 40 && !bracketFound; i++)
                {
                    foreach (var sign in new int[] { +1, -1 })
                    {
                        double off = sign * i * step;
                        var a = AreaAt(off);
                        if (a == null) continue;

                        if (Math.Abs(a.Value - targetArea) <= tolerance)
                        {
                            var finalLine = GeometryEngine.Instance.Move(splitLinePro, nx * off, ny * off) as Polyline;
                            var finalParts = GeometryEngine.Instance.Cut(selectPolygon, finalLine) as IReadOnlyList<Geometry>;
                            var a1 = GeometryEngine.Instance.Area(finalParts[0] as Polygon);
                            var a2 = GeometryEngine.Instance.Area(finalParts[1] as Polygon);
                            MessageBox.Show($"已找到偏移量: {off:F4}，第1个面面积: {a1:F4}，第2个面面积: {a2:F4}");
                            return;
                        }

                        if (prevOffset != null && prevArea != null)
                        {
                            if ((prevArea.Value - targetArea) * (a.Value - targetArea) < 0)
                            {
                                left = prevOffset.Value;
                                right = off;
                                bracketFound = true;
                                break;
                            }
                        }

                        prevOffset = off;
                        prevArea = a;
                    }
                }

                if (!bracketFound)
                {
                    MessageBox.Show("未能找到满足目标面积的偏移范围，可能切割线与多边形位置/方向不合适。");
                    return;
                }

                double bestOff = left;
                double bestErr = double.MaxValue;
                for (int iter = 0; iter < 40; iter++)
                {
                    double mid = 0.5 * (left + right);
                    var amid = AreaAt(mid);
                    if (amid == null)
                    {
                        mid = BitConverter.Int64BitsToDouble(BitConverter.DoubleToInt64Bits(mid) + 1);
                        amid = AreaAt(mid);
                        if (amid == null) break;
                    }

                    double err = Math.Abs(amid.Value - targetArea);
                    if (err < bestErr)
                    {
                        bestErr = err;
                        bestOff = mid;
                    }

                    if (Math.Abs(amid.Value - targetArea) <= tolerance)
                    {
                        bestOff = mid;
                        break;
                    }

                    var aLeft = AreaAt(left);
                    if (aLeft == null)
                    {
                        left = mid;
                        continue;
                    }

                    if ((aLeft.Value - targetArea) * (amid.Value - targetArea) < 0)
                        right = mid;
                    else
                        left = mid;
                }

                var finalSplitLine = GeometryEngine.Instance.Move(splitLinePro, nx * bestOff, ny * bestOff) as Polyline;
                var finalCut = GeometryEngine.Instance.Cut(selectPolygon, finalSplitLine) as IReadOnlyList<Geometry>;
                if (finalCut != null && finalCut.Count == 2)
                {
                    var g1 = finalCut[0] as Polygon;
                    var g2 = finalCut[1] as Polygon;
                    var area1 = Math.Abs(GeometryEngine.Instance.Area(g1));
                    var area2 = Math.Abs(GeometryEngine.Instance.Area(g2));
                    MessageBox.Show($"完成：偏移量 {bestOff:F4}，第1个面面积 {area1:F4}，第2个面面积 {area2:F4}，误差 {Math.Abs(area1 - targetArea):F6}");
                }
                else
                {
                    MessageBox.Show("最终切割未获得两个面");
                }

            });




            return true;
        }
    }
}
